/**
 *  时间插值
 *  先将t 规格化到 [0,1]
 *  然后通过 linear,easeIn, ... , 等函数 计算出一个新 t
 *  根据这个新t 使用 value 方法 对 (a,b) 进行插值.
 *
 *  如: 需要在 [1,10] 之间根据t做 sinIn 插值
 const t = 0.5;
 const a = 1;
 const b = 10;
 let new_t = myEasing.sineIn(t);

 let value = myEasing.value(t,a,b);
 let new_value = myEasing.value(new_t,a,b);
 console.log('new_value:',new_value);
 console.log('value:',value);
 *
 */
 let myEasing = {

    value(t, a, b) {
        return (1 - t) * a + t * b;
    },

    linear(t) {
        return t;
    },

    /**
     * rate > 1 开始慢 后来快
     * rate < 1 开始快 后来慢
     * @param t
     * @param rate
     * @return {number}
     */
    easeIn(t, rate) {
        return Math.pow(t, rate);
    },

    /**
     * rate > 1 开始快 后来慢
     * rate < 1 开始慢 后来快
     * @param t
     * @param rate
     * @return {number}
     */
    easeOut(t, rate) {
        return Math.pow(t, 1 / rate);
    },

    /**
     * rate > 1  两头慢  中间快
     * rate < 1  两头快  中间慢
     * @param t
     * @param rate
     * @return {number}
     */
    easeInOut(t, rate) {
        let newT = t * 2;
        if (newT < 1) {
            return 0.5 * Math.pow(newT, rate);
        } else {
            return 1.0 - 0.5 * Math.pow(2 - newT, rate);
        }
    },

    /**
     * 开始慢 后来快
     * @param t
     * @return {number}
     */
    exponentialIn(t) {
        return t === 0 ? 0 : Math.pow(2, 10 * (t - 1));
    },

    /**
     * 开始快 后来慢
     * @param t
     * @return {number}
     */
    exponentialOut(t) {
        return t === 1 ? 1 : (-(Math.pow(2, -10 * t)) + 1);
    },

    /**
     * 中间快  两头慢
     * @param t
     * @return {number}
     */
    exponentialInOut(t) {
        let newT = t * 2;
        if (newT < 1) {
            return 0.5 * Math.pow(2, 10 * (newT - 1));
        } else {
            return 0.5 * (-Math.pow(2, -10 * (newT - 1)) + 2);
        }
    },

    /**
     * 缓慢进入  开始慢 后来快
     * @param t
     * @return {number}
     */
    sineIn(t) {
        return (t === 0 || t === 1) ? t : -1 * Math.cos(t * Math.PI / 2) + 1;
    },

    /**
     * 缓慢退出  开始快 后来慢
     * @param t
     * @return {number}
     */
    sineOut(t) {
        return (t === 0 || t === 1) ? t : Math.sin(t * Math.PI / 2);
    },

    /**
     * 缓慢进入 缓慢退出  两头慢 中间快
     * @param t
     * @return {number}
     */
    sineInOut(t) {
        return (t === 0 || t === 1) ? t : -0.5 * (Math.cos(Math.PI * t) - 1);
    },

    /**
     * 从下到上慢慢变高
     * @param t
     * @param k  [0,1] k越小 弹的频率越快
     * @return {*}
     */
    elasticIn(t, k = 0.3) {
        if (t === 0 || t === 1) {
            return t;
        }
        let newT = t - 1;
        return -Math.pow(2, 10 * newT) * Math.sin((newT - (k / 4)) * Math.PI * 2 / k);
    },


    /**
     * 从上到下慢慢变高
     * @param t
     * @param k [0,1] k越小 弹的频率越快
     * @return {number}
     */
    elasticOut(t, k = 0.3) {
        return (t === 0 || t === 1) ? t : Math.pow(2, -10 * t) * Math.sin((t - (k / 4)) * Math.PI * 2 / k) + 1;
    },

    /**
     * 前后瞎弹
     * @param t
     * @param k [0,1] k越小 弹的频率越快
     * @return {number|*}
     */
    elasticInOut(t, k = 0.3) {
        let newT = 0;
        let locPeriod = k;
        if (t === 0 || t === 1) {
            newT = t;
        } else {
            newT = t * 2;
            let s = locPeriod / 4;
            newT = newT - 1;
            if (newT < 0)
                newT = -0.5 * Math.pow(2, 10 * newT) * Math.sin((newT - s) * Math.PI * 2 / locPeriod);
            else
                newT = Math.pow(2, -10 * newT) * Math.sin((newT - s) * Math.PI * 2 / locPeriod) * 0.5 + 1;
        }
        return newT;
    },


    _bounceTime(time1) {
        if (time1 < 1 / 2.75) {
            return 7.5625 * time1 * time1;
        } else if (time1 < 2 / 2.75) {
            time1 -= 1.5 / 2.75;
            return 7.5625 * time1 * time1 + 0.75;
        } else if (time1 < 2.5 / 2.75) {
            time1 -= 2.25 / 2.75;
            return 7.5625 * time1 * time1 + 0.9375;
        }

        time1 -= 2.625 / 2.75;
        return 7.5625 * time1 * time1 + 0.984375;
    },

    /**
     * 越弹越高
     * @param t
     * @return {number}
     */
    bounceIn(t) {
        return 1 - this._bounceTime(1 - t);
    },

    /**
     * bounceIn 倒过来
     * @param t
     * @return {*}
     */
    bounceOut(t) {
        return this._bounceTime(t);
    },


    /**
     *  bounceIn 和 bounceOut 连接起来
     * @param t
     * @return {number}
     */
    bounceInOut(t) {
        let newT;
        if (t < 0.5) {
            newT = t * 2;
            newT = (1 - this._bounceTime(1 - newT)) * 0.5;
        } else {
            newT = this._bounceTime(t * 2 - 1) * 0.5 + 0.5;
        }
        return newT;
    },

    /**
     * 相反的方向缓慢移动，然后加速到正确的方向
     * @param t
     * @return {number}
     */
    backIn(t) {
        let overshoot = 1.70158;
        return (t === 0 || t === 1) ? t : t * t * ((overshoot + 1) * t - overshoot);
    },

    /**
     * 先越过最大值  再返回来
     * @param t
     * @return {number}
     */
    backOut(t) {
        let overshoot = 1.70158;
        let newT = t - 1;
        return newT * newT * ((overshoot + 1) * newT + overshoot) + 1;
    },

    /**
     * 两头都越过 极值
     * @param t
     * @return {number}
     */
    backInOut(t) {
        let overshoot = 1.70158 * 1.525;
        let newT = t * 2;
        if (newT < 1) {
            return (newT * newT * ((overshoot + 1) * newT - overshoot)) / 2;
        } else {
            newT = newT - 2;
            return (newT * newT * ((overshoot + 1) * newT + overshoot)) / 2 + 1;
        }
    },

    /**
     * 3阶贝塞尔曲线来控制
     * 如:methods.bezier3(t,0,0.6,0.2,1);  需要根据实际情况去调整参数
     * @param t
     * @param a
     * @param b
     * @param c
     * @param d
     * @return {number}
     */
    bezier3(t, a, b, c, d) {
        return (Math.pow(1 - t, 3) * a + 3 * t * (Math.pow(1 - t, 2)) * b + 3 * Math.pow(t, 2) * (1 - t) * c + Math.pow(t, 3) * d);
    },

    /**
     * 2阶段,需要自己去调整
     * @param t
     * @param a
     * @param b
     * @param c
     * @return {number}
     */
    bezier2(t, a, b, c) {
        return (a * Math.pow(1 - t, 2) + 2 * b * t * (1 - t) + c * t * t);
    },

    cubicIn(t) {
        return t * t * t;
    },

    cubicOut(t) {
        t -= 1;
        return (t * t * t + 1);
    },

    cubicInOut(t) {
        t = t * 2;
        if (t < 1)
            return 0.5 * t * t * t;
        t -= 2;
        return 0.5 * (t * t * t + 2);
    },

    quadraticIn(t) {
        return Math.pow(t, 2);
    },

    quadraticOut(t) {
        return -t * (t - 2);
    },

    quadraticInOut(t) {
        let resultTime = t;
        t *= 2;
        if (t < 1) {
            resultTime = t * t * 0.5;
        } else {
            --t;
            resultTime = -0.5 * (t * (t - 2) - 1)
        }
        return resultTime;
    },

    quarticIn(t) {
        return t * t * t * t;
    },

    quarticOut(t) {
        t -= 1;
        return -(t * t * t * t - 1);
    },

    quarticInOut(t) {
        t = t * 2;
        if (t < 1)
            return 0.5 * t * t * t * t;
        t -= 2;
        return -0.5 * (t * t * t * t - 2);
    },

    circleIn(t) {
        return -1 * (Math.sqrt(1 - t * t) - 1);
    },

    circleOut(t) {
        t = t - 1;
        return Math.sqrt(1 - t * t);
    },

    circleInOut(t) {
        t = t * 2;
        if (t < 1)
            return -0.5 * (Math.sqrt(1 - t * t) - 1);
        t -= 2;
        return 0.5 * (Math.sqrt(1 - t * t) + 1);
    },
};
export default myEasing;


